﻿using System;
using System.Linq;

using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;

namespace FinlogiK.ReSharperContrib
{
	internal static class ArrangeStaticQualifierHelper
	{
		#region Methods

		internal static void AddStaticQualifier(IReferenceExpression referenceExpression)
		{
            ITypeDeclaration typeDeclaration = referenceExpression.GetContainingTypeDeclaration();
            string qualifier = BuildQualifierString(typeDeclaration.DeclaredElement);

			CSharpElementFactory factory = CSharpElementFactory.GetInstance(referenceExpression.GetPsiModule());
			IReferenceExpression qualifierExpression = factory.CreateReferenceExpression(qualifier);
			referenceExpression.SetQualifierExpression(qualifierExpression);
		}

		internal static bool IsReferenceToStaticMemberWithoutQualifier(IReferenceExpression referenceExpression)
		{
			bool result = false;

			IDeclaredElement declaredElement = referenceExpression.Reference.Resolve().DeclaredElement;

			if (IsStaticMember(declaredElement))
			{
				result = (referenceExpression.QualifierExpression == null);
			}

			return result;
		}

		private static string BuildQualifierString(ITypeElement targetType)
		{
			string qualifier = targetType.ShortName;

			if (targetType.TypeParameters.Count() > 0)
			{
				string[] genericArgumentNames = targetType.TypeParameters.Select(t => t.ShortName).ToArray();
				qualifier += "<" + string.Join(", ", genericArgumentNames) + ">";
			}

			return qualifier;
		}

		private static bool IsStaticMember(IDeclaredElement element)
		{
			IModifiersOwner modifiersOwner = element as IModifiersOwner;

			return ((modifiersOwner != null) && modifiersOwner.IsStatic && ArrangeStaticQualifierHelper.IsMemberRequiringStaticQualifier(element));
		}

		private static bool IsMemberRequiringStaticQualifier(IDeclaredElement element)
		{
			return ((element is IField) || (element is IMethod) || (element is IProperty) || (element is IEvent));
		}

		#endregion
	}
}